package com.one.react.internal;

import com.one.react.annotation.State;
import com.one.react.util.javac.TypeEnvUtils;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.model.JavacTypes;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.Context;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;

@SupportedAnnotationTypes("com.one.react.annotation.State")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class StateTransformProcessor extends AbstractProcessor {
    private Context context;
    private JavacTypes types;
    private JavacElements elements;
    private JavacTrees trees;
    private List<JCTree.JCVariableDecl> translatedVars = new ArrayList<>();
    private boolean processed;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        JavacProcessingEnvironment javacEnv = (JavacProcessingEnvironment) processingEnv;
        this.context = javacEnv.getContext();
        this.types = javacEnv.getTypeUtils();
        this.elements = javacEnv.getElementUtils();
        this.trees = JavacTrees.instance(context);
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (processed) {
            return true;
        }
        Set<? extends Element> stateVars = roundEnv.getElementsAnnotatedWith(State.class);
        for (Element stateVar : stateVars) {
            JCTree tree = trees.getTree(stateVar);
            JCTree.JCVariableDecl variableDecl = (JCTree.JCVariableDecl) tree;
            transformStateVarDecl(variableDecl);
            translatedVars.add(variableDecl);
        }
        Collection<JCTree.JCCompilationUnit> units = TypeEnvUtils.getTrees(context);
        for (JCTree.JCCompilationUnit unit : units) {
            transformStateVarAssign(unit);
            transformStateVarAccess(unit);
            System.out.println(unit);
        }
        processed = true;
        return true;
    }

    private void transformStateVarDecl(JCTree.JCVariableDecl tree) {
        FieldTypeAndInitTranslator translator = new FieldTypeAndInitTranslator(context);
        translator.scan(tree);
    }

    private void transformStateVarAssign(JCTree.JCCompilationUnit root) {
        FieldAssignTranslator translator = new FieldAssignTranslator(context, translatedVars);
        translator.scan(root, null);
    }

    private void transformStateVarAccess(JCTree.JCCompilationUnit root) {
        FieldAccessTranslator translator = new FieldAccessTranslator(context, translatedVars);
        translator.scan(root, null);
    }
}
